fi.foyt.svg.svgdom.FNISVGDocument = Class.create( {
  initialize : function() {
    this.svgNamespace = 'http://www.w3.org/2000/svg';
    this.elements = null;
    this._viewbox = null;

    this._svgNode = document.createElementNS(this.svgNamespace, "svg");
    this._svgDocument = this._svgNode.ownerDocument;
    this._svgWindow = window;
    this._svgNode.setAttribute("xmlns:svg", this.svgNamespace);
    this._svgNode.setAttribute("xmlns:fni", "http://www.foyt.fi/fnins");
    this._svgNode.setAttribute("xmlns", this.svgNamespace);
    this._initLayers();
  },
  getCurrentLayer : function() {
    return this._currentLayer;
  },
  setCurrentLayer : function(layer) {
    this._currentLayer = layer;
    this.fire("currentLayerChanged", {
      layer : layer
    });
  },
  getLayers : function() {
    var result = new Array();
    var childNodes = this._getElementChildNodes(this.getRootElement());
    for ( var i = 0; i < childNodes.length; i++) {
      var child = childNodes[i];
      if (child) {
        if ((child.tagName.toUpperCase() == 'G') && (child.getAttribute('fnigrouptype') == 'layer')) {
          result.push(childNodes[i]);
        }
      }
    }

    return result;
  },
  raiseLayer : function(layer) {
    var layers = this.getLayers();
    for ( var i = 0; i < layers.length; i++) {
      if (layers[i] == layer) {
        if (i < (layers.length - 2))
          this.getRootElement().insertBefore(layer, layers[i + 2]);
        else
          this.getRootElement().appendChild(layer);

        this.fire("layerRaised", {
          layer : layer
        });
        break;
      }
    }
  },
  lowerLayer : function(layer) {
    var layers = this.getLayers();
    for ( var i = 0; i < layers.length; i++) {
      if (layers[i] == layer) {
        if (i > 0)
          this.getRootElement().insertBefore(layer, layers[i - 1]);

        this.fire("layerLowered", {
          layer : layer
        });
        break;
      }
    }
  },
  getRootElement : function() {
    return this._svgNode;
  },
  getBackgroundGroup : function() {
    return this._background;
  },
  createElement : function(name) {
    return this._svgDocument.createElementNS(this.svgNamespace, name);
  },
  importElement : function(node) {
    try {
      return this._svgDocument.importNode(node, false);
    } catch (e) {

      var imported = this.createElement(node.tagName);
      for ( var i = 0; i < node.attributes.length; i++)
        imported.setAttribute(node.attributes[i].name, node.attributes[i].value);

      return imported;
    }

  },
  appendElement : function(parentNode, element) {
    if (this.elements == null)
      this.elements = new Array();

    this.elements.push(element);

    if (parentNode == null)
      this.getRootElement().appendChild(element);
    else
      parentNode.appendChild(element);
  },
  appendTemporaryElement : function(element) {
    this.getRootElement().appendChild(element);
    element._temporary = true;
  },
  removeTemporaryElement : function(element) {
    if (element != null) {
      if (element.parentNode != null)
        element.parentNode.removeChild(element);
      else
        addDebugText('Could not remove temporary node ' + element.tagName + ', cannot find parent...');
    }
    ;
  },
  removeElement : function(element) {
    for ( var i = 0; i < this.elements.length; i++) {
      if (this.elements[i] == element) {
        this.elements.splice(i, 1);

        while (element.childNodes.length > 0)
          this.removeElement(element.firstChild);

        element.parentNode.removeChild(element);
        break;
      }
    }
  },
  getElements : function() {
    return this.elements;
  },
  setPageSize: function (width, height) {
    var rootElement = this.getRootElement();
    rootElement.setAttribute("width", width);
    rootElement.setAttribute("height", height);
  },
  setViewBox : function(x, y, width, height) {
    this._viewbox = {
      x : x,
      y : y,
      width : width,
      height : height
    };

    var rootElement = this.getRootElement();

    rootElement.setAttribute("viewBox", x + ' ' + y + ' ' + width + ' ' + height);
  },
  getViewBox : function() {
    if (this._viewbox == null) {
      var rootElement = this.getRootElement();
      var width = rootElement.getAttribute("width");
      var height = rootElement.getAttribute("height");
      
      this._viewbox = {
        x : 0,
        y : 0,
        width : width,
        height : height
      };
    }
    
    return this._viewbox;
  },
  getElementAt : function(x, y) {
    var elements = this.getElements();
    if (elements != null) {
      for ( var i = 0; i < elements.length; i++) {
        var element = elements[i];
        var eBBox = element.getBBox();

        if ((eBBox.x <= x) && (eBBox.y <= y) && ((eBBox.x + eBBox.width) >= x) && ((eBBox.y + eBBox.height) >= y))
          return element;
      }
    }

    return null;
  },
  removeAllElements : function() {
    if (this.elements) {
      while (this.elements.length > 0) {
        var element = this.elements.pop();
        element.parentNode.removeChild(element);
      }
    }
  },
  createLayer : function(title) {
    var groupElement = this.createElement("g");
    groupElement.setAttribute("fnigrouptype", "layer");
    groupElement.setAttribute("fnilayertitle", title);

    this.getRootElement().appendChild(groupElement);

    this.fire("layerCreated", {
      layer : groupElement
    });

    return groupElement;
  },
  removeLayer : function(layer) {
    while (layer.childNodes.length > 0) {
      this.removeElement(layer.firstChild);
    }

    this.getRootElement().removeChild(layer);

    this.fire("layerRemoved", {
      layer : layer
    });
  },
  inspect : function() {
    return "[FNISVGDocument]";
  },
  getAsXML : function(width, height) {
    var xmlData = this._getSVGHeader();

    xmlData += '<svg xmlns:fni="http://www.foyt.fi/fnins" xmlns:svg="' + this.svgNamespace + '" xmlns="' + this.svgNamespace + '" ' + 'width="' + width
        + '" height="' + height + '">';

    var layers = this.getLayers();
    for (var i = 0; i < layers.length; i++)
      xmlData += this._getElementAsXML(layers[i]);

    return xmlData + "</svg>";
  },
  _getElementChildNodes: function (element) {
    return element.childNodes;
  },
  _initLayers : function() {
    this._background = this.createElement("g");
    this._background.setAttribute("fnigrouptype", "background");
    this.getRootElement().appendChild(this._background);
    this._currentLayer = null;
  },
  _getSVGHeader : function() {
    return '<?xml version="1.0" encoding="UTF-8" standalone="no"?>';
  },
  _getElementAsXML : function(element) {
    var result = '';
    
    if (element._temporary != true) {
      if (FNISVGDOMUtils.isValidSVGElement(element)) {
        result = '<' + element.tagName;
  
        var attributeNames = FNISVGDOMUtils.getElementAttributeNames(this, element);
        for (var i = 0; i < attributeNames.length; i++) {
          var attrName = attributeNames[i];
          var attrValue = element.getAttribute(attributeNames[i]);
          result += ' ' + attrName + '="' + attrValue + '"';
        }
        
        var childNodes = this._getElementChildNodes(element);
        var descendantXML = '';
        for ( var i = 0; i < childNodes.length; i++)
          descendantXML += this._getElementAsXML(childNodes[i]);
  
        if (descendantXML == '')
          result += '/>';
        else
          result += '>' + descendantXML + '</' + element.tagName + '>';
      }
    }

    return result;
  }
});

Object.extend(fi.foyt.svg.svgdom.FNISVGDocument.prototype, fni.events.FNIEventSupport);